import random

import pygame

SIZE = (500, 500)
MOVE_EVENT = pygame.USEREVENT + 1


class AudioManage:
    @staticmethod
    def play_bg():
        pygame.mixer.music.load(f"./sound/bgm.wav")
        pygame.mixer.music.play()

    @staticmethod
    def play_sound(name):
        sound = pygame.mixer.Sound(name)
        sound.play()


class FoodSprite(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load(f"{'./img/food.png' if random.random() > 0.5 else './img/food2.png'}")
        self.rect = self.image.get_rect()
        self.rect.left = random.randrange(0, 500, 25)
        self.rect.top = random.randrange(0, 500, 25)


class FoodManage:
    def __init__(self, gm):
        self.food_group = pygame.sprite.Group()
        self.gm = gm

    def generate(self):
        self.food = FoodSprite()
        self.food.add(self.food_group)

    def clear(self):
        self.food_group.empty()

    def update(self):
        self.food_group.draw(self.gm.screen)
        self.food_group.update()


class PlayerSprite(pygame.sprite.Sprite):
    def __init__(self, name, left, top):
        super().__init__()
        self.image = pygame.image.load(f"./img/{name}")
        self.rect = self.image.get_rect()
        self.rect.left = left
        self.rect.top = top

    def update(self):
        pass


class PlayerManage:
    def __init__(self, gm):
        self.player_group = pygame.sprite.Group()
        self.gm = gm

    def eat(self):
        last_pos = self.player_group.sprites()[-1].rect
        self.item = PlayerSprite("body.png", last_pos.left, last_pos.top)
        self.item.add(self.player_group)
        AudioManage.play_sound("./sound/eat.mp3")

    def born(self):
        self.score = 0
        self.dir = "left"
        self.head = PlayerSprite("left.png", 250, 250)
        self.head.add(self.player_group)
        self.item = PlayerSprite("body.png", 270, 250)
        self.item.add(self.player_group)
        self.item = PlayerSprite("body.png", 300, 250)
        self.item.add(self.player_group)

        pygame.time.set_timer(MOVE_EVENT, 400)

    def move(self, dir):
        if self.dir == "left" and dir == "right" or self.dir == "right" and dir == "left" or self.dir == "up" and dir == "down" or self.dir == "down" and dir == "up":
            pass
        else:
            if self.dir != "left" and dir == "left":
                self.head.image = pygame.image.load("./img/left.png")
            if self.dir != "right" and dir == "right":
                self.head.image = pygame.image.load("./img/right.png")
            if self.dir != "up" and dir == "up":
                self.head.image = pygame.image.load("./img/up.png")
            if self.dir != "down" and dir == "down":
                self.head.image = pygame.image.load("./img/down.png")
            self.dir = dir

            for i in range(len(self.player_group.sprites()) - 1, 0, -1):
                self.player_group.sprites()[i].rect.center = self.player_group.sprites()[i - 1].rect.center

            if self.dir == "left":
                self.head.rect.centerx -= 25
            elif self.dir == "right":
                self.head.rect.centerx += 25
            elif self.dir == "up":
                self.head.rect.centery -= 25
            elif self.dir == "down":
                self.head.rect.centery += 25

            if self.head.rect.left < 0 or self.head.rect.top < 0 or self.head.rect.right > 500 or self.head.rect.bottom > 500:
                self.die()
                self.gm.state = "end"
                self.gm.food_manage.clear()

    def die(self):
        self.player_group.empty()
        pygame.time.set_timer(MOVE_EVENT, 0)

        AudioManage.play_sound("./sound/die.wav")

    def update(self):
        if self.gm.state == "gaming":
            self.player_group.draw(self.gm.screen)
            self.player_group.update()


class UISprite(pygame.sprite.Sprite):
    def __init__(self, name, center):
        super().__init__()
        self.image = pygame.image.load(f"./img/{name}")
        self.rect = self.image.get_rect()
        self.rect.center = center

    def check_click(self):
        if pygame.mouse.get_pressed()[0]:
            pos = pygame.mouse.get_pos()
            return self.rect.collidepoint(pos)


class UIManage:
    def __init__(self, gm):
        self.gm = gm

        self.ready_group = pygame.sprite.Group()
        self.begin_btn = UISprite("begin_btn.png", (250, 250))
        self.begin_btn.add(self.ready_group)

        self.font = pygame.font.Font("./font/font.ttf", size=24)

        self.end_group = pygame.sprite.Group()
        self.restart_btn = UISprite("replay_btn.png", (250, 250))
        self.restart_btn.add(self.end_group)

    def add_score(self):
        self.gm.player_manage.score += 1
        self.score_label = self.font.render(f"Score:{self.gm.player_manage.score}", True, "red")

    def update(self):
        if self.gm.state == "ready":
            self.ready_group.draw(self.gm.screen)
            self.ready_group.update()
            if self.begin_btn.check_click():
                AudioManage.play_sound("./sound/click.mp3")
                self.gm.state = "gaming"
                self.gm.player_manage.born()
                self.gm.food_manage.generate()
                self.score_label = self.font.render(f"Score：{self.gm.player_manage.score}", True, "red")
        elif self.gm.state == "gaming":
            self.gm.screen.blit(self.score_label, (350, 20))
        elif self.gm.state == "end":
            self.end_group.draw(self.gm.screen)
            self.end_group.update()
            if self.restart_btn.check_click():
                AudioManage.play_sound("./sound/click.mp3")
                self.gm.state = "gaming"
                self.gm.player_manage.born()
                self.gm.food_manage.generate()
                self.score_label = self.font.render(f"Score：{self.gm.player_manage.score}", True, "red")


class GameManage:
    def __init__(self):
        self.state = "ready"
        self.clock = pygame.time.Clock()
        pygame.init()
        pygame.display.set_caption("贪吃蛇")
        icon = pygame.image.load("./img/favicon.ico")
        pygame.display.set_icon(icon)
        self.screen = pygame.display.set_mode(size=SIZE)
        self.ui_manage = UIManage(self)
        self.food_manage = FoodManage(self)
        self.player_manage = PlayerManage(self)

        AudioManage.play_bg()

    def check_event(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    self.player_manage.move("left")
                elif event.key == pygame.K_RIGHT:
                    self.player_manage.move("right")
                elif event.key == pygame.K_UP:
                    self.player_manage.move("up")
                elif event.key == pygame.K_DOWN:
                    self.player_manage.move("down")

            if event.type == MOVE_EVENT:
                self.player_manage.move(self.player_manage.dir)

            # 测试一剑杀死
            if event.type == pygame.KEYUP and self.state == "gaming":
                if event.key == pygame.K_SPACE:
                    self.state = "end"
                    self.player_manage.die()
                    self.food_manage.clear()

    def update_draw(self):
        self.screen.fill("#ffffcc")
        self.food_manage.update()
        self.player_manage.update()
        self.ui_manage.update()
        pygame.display.flip()

    def check_collide(self):
        if self.state == "gaming":
            r = pygame.sprite.spritecollide(self.player_manage.head, self.food_manage.food_group, True)
            if r:
                self.food_manage.generate()
                self.ui_manage.add_score()
                self.player_manage.eat()

    def main_loop(self):
        while True:
            self.clock.tick(20)
            self.check_event()
            self.check_collide()
            self.update_draw()


gm = GameManage()
gm.main_loop()
